package com.weiiew.backend.operationUtils;

import com.weiiew.backend.entity.TerminationPolicy;
import com.weiiew.backend.entity.enums.ExecutorState;
import com.weiiew.backend.entity.enums.LogState;
import com.weiiew.backend.operation.ComputerOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.simp.SimpMessagingTemplate;

import java.awt.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 统一的操作执行器，支持多线程、暂停、加载、启动
 * 确保终止条件只有一个
 *
 * @author 魏锴
 * @since 2025/5/3
 */
@Slf4j
public class OperationExecutor {
    // 执行控制状态
    private final AtomicReference<ExecutorState> state = new AtomicReference<>();
    private final AtomicInteger executionCount = new AtomicInteger(0); // 操作序列执行次数
    private final AtomicInteger currentIndex = new AtomicInteger(0); // 当前执行操作的索引

    // 倒计时相关组件
    private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
    private final AtomicInteger countdown = new AtomicInteger(3);
    private final CountDownLatch countdownLatch = new CountDownLatch(1);
    // 执行相关资源
    private ComputerOperation[] operations; // 操作列表
    private final Robot robot;
    private final Object stateLock = new Object();
    private final Object runLock = new Object();
    private ScheduledFuture<?> countdownTask;
    // 停止条件配置
    private volatile TerminationPolicy policy;
    private volatile LogState logState;
    private volatile long startTime = 0; // 开始执行时间
    private volatile long timeOffset = 0; // 偏移时间
    private volatile long sequenceStartTime = 0; // 序列开始执行时间
    private volatile long sequenceTimeOffset = 0; // 序列偏移时间
    private ExecutorCommunicationTool tool; // 用于前后端通讯
    // 是否应该停止
    private Thread executionThread; // 执行线程

    public OperationExecutor() throws AWTException {
        this.operations = new ComputerOperation[0];
        // 解包为数组减小接下来判断的时间
        this.tool = new ExecutorCommunicationTool();
        this.robot = new Robot();
        this.logState = LogState.NONE;
        initResource();
    }

    public synchronized void setOperations(OperationSequence sequence) {
        if (state.get() != ExecutorState.READY && state.get() != ExecutorState.STOP)
            throw new IllegalStateException("The " + state.get() + " status does not support set operations");
        this.operations = sequence.getOperations().toArray(new ComputerOperation[0]);
    }

    public synchronized void setLogger(SimpMessagingTemplate template, String channel) {
        if (state.get() != ExecutorState.READY && state.get() != ExecutorState.STOP)
            throw new IllegalStateException("The " + state.get() + " status does not support set logger");
        this.tool = new ExecutorCommunicationTool(template, channel);
    }

    /**
     * 设置停止条件
     *
     * @param policy 停止条件
     */
    public synchronized void setTerminationPolicy(TerminationPolicy policy) {
        if (state.get() != ExecutorState.READY && state.get() != ExecutorState.STOP)
            throw new IllegalStateException("The " + state.get() + " status does not support set stop policy");
        this.policy = policy;
    }

    /**
     * 设置日志输出级别
     *
     * @param logState 日志输出级别
     */
    public synchronized void setLogState(LogState logState) {
        if (state.get() != ExecutorState.READY && state.get() != ExecutorState.STOP)
            throw new IllegalStateException("The " + state.get() + " status does not support set log level");
        this.logState = logState;
    }

    /**
     * 倒计时函数
     */
    private void startCountdown(Runnable callback) {
        countdown.set(4);
        state.set(ExecutorState.COUNTDOWN); // 设置为倒计时状态
        countdownTask = scheduler.scheduleAtFixedRate(() -> {
            if (state.get() != ExecutorState.COUNTDOWN) {
                countdownTask.cancel(true);
                countdownLatch.countDown();
                if (this.logState != LogState.NONE)
                    tool.focusedSendMessage(state.get(), currentIndex.get(), "倒计时被取消");
                return;
            }
            int remaining = countdown.decrementAndGet();
            if (remaining > 0) {
                if (this.logState != LogState.NONE)
                    tool.focusedSendMessage(state.get(), currentIndex.get(), "倒计时: {} 秒", remaining);
            } else if (remaining == 0) {
                if (this.logState != LogState.NONE)
                    tool.focusedSendMessage(state.get(), currentIndex.get(), "倒计时结束!");
                countdownTask.cancel(true);
                countdownLatch.countDown();
                callback.run();
            }
        }, 0, 1, TimeUnit.SECONDS);
    }

    private void stopCountdown() {
        countdownTask.cancel(true);
        countdownLatch.countDown();
        if (this.logState != LogState.NONE)
            tool.focusedSendMessage(state.get(), 0, "倒计时已取消");
    }

    public boolean judgeSequenceState() {
        if (policy == null) {
            throw new IllegalStateException("Termination policy is not set");
        }
        if (policy.getType() == TerminationPolicy.StopType.DURATION) {
            long runTime = System.currentTimeMillis() - startTime;
            return runTime <= policy.getMaxTime();
        }
        return true;
    }

    public void judgeState() {
        if (policy == null) {
            throw new IllegalStateException("Termination policy is not set");
        }
        synchronized (stateLock) {
            boolean isLogger = this.logState.isLoggableSequence();
            if (state.get() == ExecutorState.STOP) {
                if (isLogger) tool.focusedSendMessage(state.get(),
                        currentIndex.get(), "执行器终止，手动终止");
            }
            if (policy.getType() == TerminationPolicy.StopType.FOREVER) {
                if (isLogger) tool.sendMessage(state.get(), currentIndex.get(),
                        "执行器执行次数{}次， 执行时间{}ms",
                        executionCount.get(), System.currentTimeMillis() - startTime);
            } else if (policy.getType() == TerminationPolicy.StopType.DURATION) {
                long runTime = System.currentTimeMillis() - startTime;
                if (runTime > policy.getMaxTime()) {
                    state.set(ExecutorState.STOP);
                    if (isLogger) tool.focusedSendMessage(state.get(), currentIndex.get(),
                            "执行器终止，达到最大执行时间{}",
                            policy.getMaxTime());
                } else {
                    if (isLogger) tool.sendMessage(state.get(), currentIndex.get(),
                            "执行器执行时间 {}ms / {}ms",
                            runTime, policy.getMaxTime());
                }
            } else {
                if (executionCount.get() >= policy.getMaxExecutions()) {
                    state.set(ExecutorState.STOP);// 达到终止条件
                    if (isLogger) tool.focusedSendMessage(state.get(), 0, // 为了使得当序列执行完毕后能够回到第一条
                            "执行器终止，达到最大执行次数{}",
                            policy.getMaxExecutions());
                } else {
                    if (isLogger) tool.sendMessage(state.get(), currentIndex.get(),
                            "执行器执行次数 {} / {}",
                            executionCount.get(), policy.getMaxExecutions());
                }
            }
        }
    }

    /**
     * 主体运行函数，主要负责整个操作序列的执行和判断
     */
    private void execute() {
        this.executionCount.set(0); // 重置执行次数
        startTime = System.currentTimeMillis();
        while (state.get() != ExecutorState.STOP) {
            executeSingleSequence();
            executionCount.incrementAndGet();
            judgeState();
        }
        // 清理资源
        clearResource();
    }

    /**
     * 操作序列执行函数，主要负责单次操作序列的执行
     */
    private void executeSingleSequence() {
        sequenceStartTime = System.currentTimeMillis();
        sequenceTimeOffset = 0;
        currentIndex.set(0); // 重置索引
        //judgeSequenceState负责判断时间是否超时
        while (currentIndex.get() < operations.length
                && state.get() != ExecutorState.STOP
                && judgeSequenceState()) {
            // 当它处于倒计时和暂停状态时等待
            while ((state.get() == ExecutorState.PAUSE)
                    || (state.get() == ExecutorState.COUNTDOWN)) {
                if (state.get() == ExecutorState.PAUSE)
                    tool.focusedSendMessage(state.get(), currentIndex.get(), "执行器已被暂停");
                synchronized (runLock) {
                    try {
                        log.info("开始等待，当前状态：{}", state.get());
                        runLock.wait();
                        log.info("已被唤醒，当前状态：{}", state.get());
                    } catch (InterruptedException e) {
                        log.info("等待被中断，当前状态：{}", state.get());
                    }
                }
            }
            log.info("elapsed:{}", System.currentTimeMillis() - sequenceStartTime);
            if (state.get() == ExecutorState.STOP) return;

            ComputerOperation op = operations[currentIndex.get()];
            long elapsed = System.currentTimeMillis() - sequenceStartTime;
            long delay = op.getTimestamp() - elapsed;
            log.info("elapsed:{}, delay: {}", elapsed, delay);
            // 精确等待实现
            if (delay > 0) {
                try {
                    Thread.sleep(delay);
                } catch (InterruptedException e) {
                    continue; // 当暂停被中断后重新开始这个操作执行
                }
            }
            if (state.get() != ExecutorState.RUNNING) continue; // 非执行状态全部重新开始
            // 执行操作
            try {
                op.execute(robot);
                robot.waitForIdle();
            } catch (Exception ignored) {
            }
            if (logState.isLoggableOperation())
                tool.sendMessage(state.get(), currentIndex.get(),
                        "执行第{}个操作：{}", currentIndex.get(), op);
            currentIndex.incrementAndGet();
        }
    }

    private void initResource() {
        synchronized (stateLock) {
            this.executionThread = new Thread(this::execute);
            this.state.set(ExecutorState.READY);
        }
    }

    /**
     * 清空资源
     */
    private void clearResource() {
        synchronized (stateLock) {
            state.set(ExecutorState.STOP);
            currentIndex.set(0);
            if (executionThread != null && executionThread.isAlive()) {
                executionThread.interrupt();
            }
        }
    }

    /**
     * 暴露外部的接口
     */
    public void start() {
        synchronized (stateLock) {
            if (state.get() != ExecutorState.READY && state.get() != ExecutorState.STOP)
                throw new IllegalStateException("The " + state.get() + " status does not support start operation");
            if (state.get() == ExecutorState.STOP) initResource();
            startCountdown(() -> {
                synchronized (stateLock) {
                    synchronized (runLock) {
                        startTime = System.currentTimeMillis();
                        sequenceStartTime = System.currentTimeMillis();
                        state.set(ExecutorState.RUNNING);
                        runLock.notifyAll();
                    }
                }
            });
            //优先设置状态COUNTDOWN
            this.executionThread.start(); //统一在start中启动防止出现READY报错
        }
    }

    public void stop() {
        synchronized (stateLock) {
            if (state.get() != ExecutorState.RUNNING && state.get() != ExecutorState.PAUSE && state.get() != ExecutorState.COUNTDOWN)
                throw new IllegalStateException("The " + state.get() + " current status does not support stop operation");
            if (state.get() == ExecutorState.COUNTDOWN) stopCountdown();
            state.set(ExecutorState.STOP);
            executionThread.interrupt();
        }
    }

    public void pause() {
        synchronized (stateLock) {
            if (state.get() != ExecutorState.RUNNING && state.get() != ExecutorState.COUNTDOWN)
                throw new IllegalStateException("The " + state.get() + " status does not support pause operation");
            if (state.get() == ExecutorState.COUNTDOWN) stopCountdown();
            timeOffset = System.currentTimeMillis() - startTime; // 获取时间偏移
            sequenceTimeOffset = System.currentTimeMillis() - sequenceStartTime; // 序列时间偏移
            state.set(ExecutorState.PAUSE);
            executionThread.interrupt();
        }
    }

    public void resume() {
        synchronized (stateLock) {
            if (state.get() != ExecutorState.PAUSE)
                throw new IllegalStateException("The " + state.get() + " status does not support restart operation");
            startCountdown(() -> {
                synchronized (stateLock) {
                    synchronized (runLock) {
                        startTime = System.currentTimeMillis() - timeOffset;
                        sequenceStartTime = System.currentTimeMillis() - sequenceTimeOffset;
                        state.set(ExecutorState.RUNNING);
                        runLock.notifyAll(); // 在持有锁的情况下唤醒
                        log.info("激活lock, 状态：（{}, {}, {}）", state.get(), startTime, sequenceStartTime);
                    }
                }
            });
        }
    }

    // 重置操作
    public void reset() {
        synchronized (stateLock) {
            if (state.get() != ExecutorState.PAUSE)
                throw new IllegalStateException("The " + state.get() + " status does not support reset operation");
            timeOffset = 0; // 重置时间偏移
            sequenceTimeOffset = 0; // 重置序列时间偏移
            currentIndex.set(0); // 重置临时index
            executionCount.set(0); // 重置执行次数
            tool.sendMessage(state.get(), currentIndex.get(), "执行器已被重置");
        }
    }

    public void toggle() {
        synchronized (stateLock) {
            switch (state.get()) {
                case READY:
                    log.info("ready");
                    start();
                    break;
                case RUNNING:
                    log.info("running");
                    pause();
                    break;
                case PAUSE:
                    log.info("pause");
                    resume();
                    break;
                case STOP:
                    log.info("stop");
                    start();
                    break;
                case COUNTDOWN:
                    log.info("countdown");
                    pause();
            }
        }
    }

    /**
     * 启动/停止切换函数，仅处理启动和停止的切换（与toggle区分）
     */
    public void startStopToggle() {
        synchronized (stateLock) {
            if (state.get() == ExecutorState.RUNNING ||
                    state.get() == ExecutorState.PAUSE ||
                    state.get() == ExecutorState.COUNTDOWN) {
                // 如果处于运行、暂停或倒计时状态，则执行停止
                stop();
            } else if (state.get() == ExecutorState.STOP ||
                    state.get() == ExecutorState.READY) {
                // 如果处于停止或就绪状态，则执行启动
                start();
            }
        }
    }

    public ExecutorState getState() {
        return state.get();
    }
}
